#include "const/oPreDefine.h"
#include "platform/oAICache.h"
#include "platform/oTypes.h"
#include "platform/oAINode.h"
#include "platform/oAI.h"
using namespace platform;
#include "misc/oContent.h"
#define oCase case oAIXml

oRelation oAICache::relation = e_unkown;

string oAICache::propName;

uint32 oAICache::type;

uint32 oAICache::action;

int oAICache::tag = 0;

oCompare* oAICache::compareOne = nullptr;

oCompare* oAICache::compareTwo = nullptr;

oAICache::oAICache()
{
	_parser.setDelegator(this);
}

oAICache::~oAICache()
{
	oAICache::unload();
}

oAICache& oAICache::sharedCache()
{
	static oAICache aiCache;
	return aiCache;
}

void oAICache::load( const char* filename )
{
	unsigned long size;
	char* data = oSharedContent.loadFile(filename, size);
	_parser.parseData(data, size);
	CC_SAFE_DELETE_ARRAY(data);
}

void oAICache::unload()
{
	BOOST_FOREACH(const oReflexMap::value_type& item, _reflexArcs)
	{
		item.second->release();
	}
	_reflexArcs.clear();
	BOOST_FOREACH(const oInstinctMap::value_type& item, _instincts)
	{
		item.second->release();
	}
	_instincts.clear();
}

oAILeaf* oAICache::getReflexArc( const string& name )
{
	auto it = _reflexArcs.find(name);
	return it != _reflexArcs.end() ? it->second : nullptr;
}

oInstinct* oAICache::getInstinct( const string& name )
{
	auto it = _instincts.find(name);
	return it != _instincts.end() ? it->second : nullptr;
}

void oAICache::textHandler( void *ctx, const char *s, int len )
{ }

void oAICache::startElement( void *ctx, const char *name, const char **atts )
{
	switch (name[0])
	{
		oCase::Reflection:
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Name:
						_currentItemName = atts[++i];
						break;
				}
			}
			break;
		oCase::Instinct:
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Name:
						_currentItemName = atts[++i];
						break;
					oCase::Property:
						_propName = atts[++i];
						break;
				}
			}
			break;
		oCase::SelNode:
			_nodeStack.push(oSelNode::create());
			break;
		oCase::SeqNode:
			_nodeStack.push(oSeqNode::create());
			break;
		oCase::ParSelNode:
			_nodeStack.push(oParSelNode::create());
			break;
		oCase::ParSeqNode:
			_nodeStack.push(oParSeqNode::create());
			break;
		oCase::ConNode:
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::ID:
						_conIndex = atoi(atts[++i]);
						break;
					oCase::Relation:
						oAICache::relation = (oRelation)atoi(atts[++i]);
						break;
					oCase::Action:
						oAICache::action = atoi(atts[++i]);
						break;
					oCase::Type:
						oAICache::type = atoi(atts[++i]);
						break;
					oCase::Tag:
						oAICache::tag = atoi(atts[++i]);
						break;
				}
			}
			break;
		oCase::ActNode:
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::ID:
						oAICache::action = atoi(atts[++i]);
						_nodeStack.push(oActNode::create());
						break;
				}
			}
			break;
		oCase::Exp:
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Op:
						_op = (uint32)atoi(atts[++i]);
						break;
				}
			}
			break;
		oCase::Val:
		{
			uint32 op;
			float value;
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Op:
						op = (uint32)atoi(atts[++i]);
						break;
					oCase::Value:
						value = (float)atof(atts[++i]);
						break;
				}
			}
			_compareStack.push(new oValCompare(op, value));
			break;
		}
		oCase::True:
			_compareStack.push(new oTrue());
			break;
		oCase::False:
			_compareStack.push(new oFalse());
			break;
	}
}

void oAICache::endElement( void *ctx, const char *name )
{
	switch (name[0])
	{
		oCase::SelNode:
		oCase::SeqNode:
		oCase::ParSelNode:
		oCase::ParSeqNode:
			{
				oAINode* node = ((oAINode*)(_nodeStack.top()));
				_nodeStack.pop();
				if (!_nodeStack.empty())
				{
					((oAINode*)(_nodeStack.top()))->addChild(node);
				}
				else
				{
					_nodeStack.push(node);
				}
			}
			break;
		oCase::ActNode:
			break;
		oCase::ConNode:
			{
				oAILeaf* node = oConNode::create(_conIndex);
				if (!_nodeStack.empty())
				{
					((oAINode*)(_nodeStack.top()))->addChild(node);
				}
				else
				{
					_nodeStack.push(node);
				}
			}
			break;
		oCase::Reflection:
			{
				oAILeaf* node = _nodeStack.top();
				_nodeStack.pop();
				node->retain();
				_reflexArcs[_currentItemName] = node;
			}
			break;
		oCase::Instinct:
			{
				oAILeaf* node = _nodeStack.top();
				_nodeStack.pop();
				oInstinct* instinct = oInstinct::create(_propName, node);
				instinct->retain();
				_instincts[_currentItemName] = instinct;
			}
			break;
		oCase::Exp:
			{
				oCompare* one = _compareStack.top();
				_compareStack.pop();
				oCompare* two = _compareStack.top();
				_compareStack.pop();
				oCompare* exp = new oExpCompare(one, _op, two);
				_compareStack.push(exp);
			}
			break;
		oCase::Compare:
			{
				oCompare* cmp = _compareStack.top();
				_compareStack.pop();
				if (oAICache::compareOne)
				{
					oAICache::compareTwo = cmp;
				}
				else
				{
					oAICache::compareOne = cmp;
				}
			}
			break;
	}
}
